package com.gitee.flow.ext;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.Duration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.flowable.common.engine.api.delegate.Expression;
import org.flowable.task.service.delegate.DelegateTask;
import org.flowable.task.service.delegate.TaskListener;

/**
 * 到期日设置，任务逾期时间设定.
 *
 * @author CGD
 *
 */
public class DueDateHandler implements TaskListener {

  private static final long serialVersionUID = 1L;

  private static final Log log = LogFactory.getLog(DueDateHandler.class);

  /**
   * 时间间隔表达式 ，符合 ISO 8601 规范 非工作日 P[n]Y[n]M[n]DT[n]H[n]M[n]S 工作日 BP[n]Y[n]M[n]DT[n]H[n]M[n]S.
   */
  private Expression period;

  /*
   * (non-Javadoc).
   * 
   * @see
   * org.activiti.engine.delegate.TaskListener#notify(org.activiti.engine.delegate.DelegateTask)
   */
  public void notify(DelegateTask delegateTask) {
    String expText = period.getExpressionText();
    LocalDateTime dueDate = getDueDate(expText);
    Date date = Date.from(dueDate.atZone(ZoneId.systemDefault()).toInstant());
    delegateTask.setDueDate(date);
  }

  /**
   * 获取截止日期 DueDate.
   *
   * @param expText 表达式
   */
  public LocalDateTime getDueDate(String expText) {
    LocalDateTime dueDate = LocalDateTime.now();
    if (isBusinessDay(expText)) {
      // 工作日
      expText = expText.substring(1);
      // TODO 计算工作日
    } else {
      Duration duration = parsePeriod(expText);
      dueDate = dueDate.plusSeconds(duration.getSeconds() * duration.getSign());
      dueDate = dueDate.plusMinutes(duration.getMinutes() * duration.getSign());
      dueDate = dueDate.plusHours(duration.getHours() * duration.getSign());
      dueDate = dueDate.plusDays(duration.getDays() * duration.getSign());
      dueDate = dueDate.plusMonths(duration.getMonths() * duration.getSign());
      dueDate = dueDate.plusYears(duration.getYears() * duration.getSign());
    }
    return dueDate;
  }

  /**
   * 判断是否是工作日表达式.
   */
  private boolean isBusinessDay(String period) {
    return period.startsWith("B");
  }

  /**
   * 获取持续时间.
   *
   * @param period ISO 8061 标准的表达式
   */
  private Duration parsePeriod(String period) {
    DatatypeFactory datatypeFactory = null;
    try {
      datatypeFactory = DatatypeFactory.newInstance();
    } catch (DatatypeConfigurationException e) {
      log.error(e.getLocalizedMessage());
    }
    return datatypeFactory.newDuration(period);
  }

}
